home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / machserver / 1.098 / fsutil / fsutilHandle.c < prev    next >
C/C++ Source or Header  |  1991-04-12  |  38KB  |  1,306 lines

  1. /* 
  2.  * fsutilHandle.c --
  3.  *
  4.  *    Routines to manage file handles.  They are kept in a table hashed
  5.  *    by the Fs_FileID type.  They are referenced counted and eligible for
  6.  *    removal when their reference count goes to zero.  Fsutil_HandleInstall
  7.  *    adds handles to the table.  Fsutil_HandleFetch returns a locked handle.
  8.  *    Fsutil_HandleLock locks a handle that you already have.
  9.  *    Installing initializes the refCount to 1, and Fetching increments it.
  10.  *    Use Fsutil_HandleUnlock and Fsutil_HandleReleaseHdr to unlock and
  11.  *    decrement the reference count, respectively.  The macros
  12.  *    Fsutil_HandleFetchType and Fsutil_HandleRelease do type casting and
  13.  *    are defined in fsInt.h.  Fsutil_HandleRemove deletes a handle from
  14.  *    the table, and Fsutil_GetNextHandle is used to iterate through the
  15.  *    whole hash table.
  16.  *
  17.  * Copyright 1986 Regents of the University of California.
  18.  * All rights reserved.
  19.  */
  20.  
  21. #ifndef lint
  22. static char rcsid[] = "$Header: /sprite/src/kernel/fsutil/RCS/fsutilHandle.c,v 9.6 91/04/12 17:34:45 kupfer Exp $ SPRITE (Berkeley)";
  23. #endif not lint
  24.  
  25. #include <sprite.h>
  26. #include <fs.h>
  27. #include <fsutil.h>
  28. #include <fsStat.h>
  29. #include <fslcl.h>
  30. #include <fsdm.h>
  31. #include <fsio.h>
  32. #include <fsutilTrace.h>
  33. #include <fsNameOps.h>
  34. #include <hash.h>
  35.  
  36. #include <string.h>
  37. #include <stdio.h>
  38.  
  39. static Sync_Lock handleTableLock = Sync_LockInitStatic("Fs:handleTable");
  40. #define    LOCKPTR    &handleTableLock
  41.  
  42. /*
  43.  * Synchronization and termination variables for LRU replacement.
  44.  */
  45. Sync_Condition lruDone;
  46. static Boolean lruInProgress;
  47. static int lruHandlesChecked;
  48. /*
  49.  * NOTE: The current implementation of handle scavenging leads to serious
  50.  * performance problems.  On systems with large file caches almost all the
  51.  * handles on the LRU will have files in the cache and wont be scavenged.
  52.  * Everytime a new handle needs to be created the entire LRU is scanned 
  53.  * before the code gives up and malloc's memory. This needs to be fixed. 
  54.  */
  55.  
  56. /*
  57.  * Hash tables for object handles.  These are kept in LRU order and
  58.  * a soft limit on their number is enforced.  If the number of handles
  59.  * gets beyond fs_Stats.handle.maxNumber then LRU replacement is done until
  60.  * handleScavengeThreashold are replaced.  If all handles are in
  61.  * use the max table size is allowed to grow by handleLimitInc.
  62.  * The table never shrinks on the premise that once it has grown the
  63.  * memory allocator establishes a high water mark and shrinking the table
  64.  * won't really help overall kernel memory usage.
  65.  */
  66. Hash_Table    fileHashTableStruct;
  67. Hash_Table    *fileHashTable = &fileHashTableStruct;
  68. static List_Links lruListHeader;
  69. static List_Links *lruList = &lruListHeader;
  70. /*
  71.  * FS_HANDLE_TABLE_SIZE is the initial size of the handle table.
  72.  *    Observation reveals that it takes about 120 handles to get
  73.  *    through multi-user bootstrap, and 135 to get through the first login.
  74.  *    Starting the window system jumps the number of handles to about 250.
  75.  *    Running a large compilation pushes the table up to about 450 handles.
  76.  *    The file servers ramp up to 2500 handles, but this is a
  77.  *    function of the activity of their clients and the number of
  78.  *    directories they have.
  79.  * LIMIT_INC defines the amount the table grows by
  80.  * THREASHOLD defines how many handles are reclaimed before stopping.  This
  81.  *    is set very low so in the steady state we don't waste much time
  82.  *    looking at un-reclaimable handles.
  83.  */
  84. #define        FS_HANDLE_TABLE_SIZE       400
  85.  
  86. #define        LIMIT_INC(max)           ( 100 )
  87. int        handleLimitInc =       LIMIT_INC(FS_HANDLE_TABLE_SIZE);
  88. #define        THREASHOLD(max)           ( 1 )
  89. int        handleScavengeThreashold = THREASHOLD(FS_HANDLE_TABLE_SIZE);
  90.  
  91. extern Fs_HandleHeader *GetNextLRUHandle _ARGS_((void));
  92. extern void DoneLRU _ARGS_((int numScavenged));
  93.  
  94. /*
  95.  * Flags for handles referenced from the hash table.
  96.  *    FS_HANDLE_INSTALLED - the structure has been put into the hash table.
  97.  *    FS_HANDLE_LOCKED    - the lock bit on the handle.  Handles are locked
  98.  *        when they are fetched from the hash table.
  99.  *    FS_HANDLE_REMOVED   - set instead of freeing the handle if the
  100.  *        remove procedure sees the 'wanted' or 'don't move' bit.
  101.  *    FS_HANDLE_INVALID   - set when a handle becomes invalid after
  102.  *        a recovery error.
  103.  *    FS_HANDLE_DONT_CACHE - set if the handle should be removed after
  104.  *        the last reference is released.
  105.  */
  106. #define FS_HANDLE_INSTALLED    0x1
  107. #define FS_HANDLE_LOCKED    0x2
  108. #define FS_HANDLE_REMOVED    0x8
  109. #define FS_HANDLE_FREED        0x10
  110. #define FS_HANDLE_INVALID    0x20
  111. #define FS_HANDLE_DONT_CACHE    0x40
  112.  
  113. /*
  114.  * LOCK_HANDLE --
  115.  * Macro to lock a file handle.   The handle lock is used during open/close
  116.  * and migration to serialize fetching, releasing, installing,
  117.  * and removing the handle.  Additionally, some object types use the
  118.  * handle lock for synchronization of I/O operations.
  119.  * If CLEAN is defined we don't remember the process ID of the locker,
  120.  * nor do we count events.
  121.  */
  122.  
  123. #ifdef CLEAN
  124.  
  125. #define    LOCK_HANDLE(hdrPtr) \
  126.     while (((hdrPtr)->flags & FS_HANDLE_LOCKED) && !sys_ShuttingDown) { \
  127.         (void) Sync_Wait(&((hdrPtr)->unlocked), FALSE); \
  128.     } \
  129.     (hdrPtr)->flags |= FS_HANDLE_LOCKED;
  130.  
  131. #else
  132.  
  133. #define LOCK_HANDLE(hdrPtr) \
  134.     while (((hdrPtr)->flags & FS_HANDLE_LOCKED) && !sys_ShuttingDown) { \
  135.         fs_Stats.handle.lockWaits++; \
  136.         (void) Sync_Wait(&((hdrPtr)->unlocked), FALSE); \
  137.     } \
  138.     fs_Stats.handle.locks++; \
  139.     (hdrPtr)->lockProcPtr = Proc_GetEffectiveProc(); \
  140.     (hdrPtr)->flags |= FS_HANDLE_LOCKED;
  141.  
  142. #endif
  143.  
  144. /*
  145.  * UNLOCK_HANDLE --
  146.  *    Unlock a handle so it can be fetched by another process.
  147.  *    This clears the lock bit and notifies the waiting condition.
  148.  */
  149.  
  150. #ifdef CLEAN
  151.  
  152. #define    UNLOCK_HANDLE(hdrPtr) \
  153.     (hdrPtr)->flags &= ~FS_HANDLE_LOCKED; \
  154.     Sync_Broadcast(&((hdrPtr)->unlocked));
  155.  
  156. #else
  157.  
  158. #define    UNLOCK_HANDLE(hdrPtr) \
  159.     (hdrPtr)->flags &= ~FS_HANDLE_LOCKED; \
  160.     (hdrPtr)->lockProcPtr = (Proc_ControlBlock *)NIL; \
  161.     fs_Stats.handle.unlocks++; \
  162.     Sync_Broadcast(&((hdrPtr)->unlocked));
  163.  
  164. #endif
  165. /*
  166.  * REMOVE_HANDLE --
  167.  * Macro to remove a handle, so no details get fogotten.  Note, removal
  168.  * from the hash table is separate, because we do that first, and then
  169.  * clean it up completely later with this macro.
  170.  */
  171.  
  172. #define REMOVE_HANDLE(hdrPtr) \
  173.     if ((hdrPtr)->lruLinks.nextPtr != (List_Links *)NIL) {    \
  174.         List_Remove(&(hdrPtr)->lruLinks);             \
  175.         fs_Stats.handle.lruEntries--;            \
  176.     }                            \
  177.     if ((hdrPtr)->name != (char *)NIL) {            \
  178.         free((hdrPtr)->name);                \
  179.     }                            \
  180.     free((char *)(hdrPtr));
  181.  
  182. /*
  183.  * MOVE_HANDLE --
  184.  * Macro to move a handle to the back (most recent) end of the LRU list.
  185.  * Not all handle types are in the LRU list, hence the check against NIL.
  186.  */
  187.  
  188. #define MOVE_HANDLE(hdrPtr) \
  189.         if ((hdrPtr)->lruLinks.nextPtr != (List_Links *)NIL) {    \
  190.         List_Move(&(hdrPtr)->lruLinks, LIST_ATREAR(lruList));    \
  191.         }
  192.  
  193. /*
  194.  * HDR_FILE_NAME --
  195.  * Macro to give name associated with a handle.
  196.  */
  197. #define HDR_FILE_NAME(hdrPtr) \
  198.     (((hdrPtr)->name == (char *)NIL) ? "(no name)" : hdrPtr->name)
  199.  
  200. /*
  201.  * Macro for debug trace prints.
  202.  */
  203. int fsHandleTrace = FALSE;
  204. #ifndef CLEAN
  205. #define HANDLE_TRACE(hdrPtr, comment) \
  206.     if (fsHandleTrace) {                        \
  207.     printf("<%d, %d, %d, %d> flags %x ref %d : %s\n",        \
  208.     (hdrPtr)->fileID.type, (hdrPtr)->fileID.serverID,        \
  209.     (hdrPtr)->fileID.major, (hdrPtr)->fileID.minor,            \
  210.     (hdrPtr)->flags, (hdrPtr)->refCount, comment);            \
  211.     }
  212. #else
  213. #define HANDLE_TRACE(hdrPtr, comment)
  214. #endif
  215.  
  216. extern Boolean HandleInstallInt _ARGS_((Fs_FileID *fileIDPtr, 
  217.         unsigned int handleLimit, Fs_HandleHeader **hdrPtrPtr, 
  218.         Boolean *foundPtr, Boolean returnLocked));
  219.  
  220.  
  221. /*
  222.  *----------------------------------------------------------------------------
  223.  *
  224.  * Fsutil_HandleInit --
  225.  *
  226.  *     Initialize the hash table.
  227.  *
  228.  * Results:
  229.  *    None.
  230.  *
  231.  * Side effects:
  232.  *    Hash table is initialized.
  233.  *
  234.  *----------------------------------------------------------------------------
  235.  */
  236.  
  237. void
  238. Fsutil_HandleInit(fileHashSize)
  239.     int    fileHashSize;    /* The number of hash table entries to put in the
  240.              * file hash table for starters. */
  241. {
  242.     /*
  243.      * Set the initial number of handle to be the maximum of 
  244.      * FS_HANDLE_TABLE_SIZE and 1/4 of the maximum number of blocks in the
  245.      * file cache.  This hack prevents the large overheads from
  246.      * the initial growing of the handle table. 
  247.      */
  248.     fs_Stats.handle.maxNumber = FS_HANDLE_TABLE_SIZE;
  249.     if (fs_Stats.handle.maxNumber < fs_Stats.blockCache.maxNumBlocks/4) {
  250.     fs_Stats.handle.maxNumber = fs_Stats.blockCache.maxNumBlocks/4;
  251.     }
  252.     List_Init(lruList);
  253.     Hash_Init(fileHashTable, fileHashSize, Hash_Size(sizeof(Fs_FileID)));
  254. }
  255.  
  256.  
  257. /*
  258.  *----------------------------------------------------------------------------
  259.  *
  260.  * Fsutil_HandleInstall --
  261.  *
  262.  *      Install a file handle given its fileID.  The caller is responsible
  263.  *    for initializing type-specific fields if this procedure returns
  264.  *    FALSE to indicate the handle was newly created.  The handle is
  265.  *    returned locked and with a single reference that has to be
  266.  *    released with Fsutil_HandleRelease.
  267.  *
  268.  * Results:
  269.  *    TRUE is returned if the file handle was already in the 
  270.  *    hash table.  Upon return, *hdrPtrPtr references the installed handle.
  271.  *
  272.  * Side effects:
  273.  *    New handle may be allocated and installed into the hash table.
  274.  *
  275.  *----------------------------------------------------------------------------
  276.  *
  277.  */
  278. ENTRY Boolean
  279. Fsutil_HandleInstall(fileIDPtr, size, name, cantBlock, hdrPtrPtr)
  280.     register Fs_FileID    *fileIDPtr;    /* Identfies handle to install. */
  281.     int             size;        /* True size of the handle.  This
  282.                      * routine only looks at the header,
  283.                      * but more data follows that. */
  284.     char        *name;        /* File name for error messages */
  285.     Boolean        cantBlock;    /* TRUE if this call shouldn't block
  286.                      * because the handle already is locked.
  287.                      */
  288.     Fs_HandleHeader    **hdrPtrPtr;    /* Return pointer to handle that
  289.                      * is found in the hash table. */
  290. {
  291.     Boolean found;
  292.     Boolean tableFull;
  293.     int numScavenged;
  294.     Fs_HandleHeader *hdrPtr;
  295.     Fs_HandleHeader *newHdrPtr = (Fs_HandleHeader *)NIL;
  296.     Boolean returnLocked = TRUE;    /* For now, always return locked */
  297.  
  298.     fs_Stats.handle.installCalls++;
  299.     do {
  300.     Boolean wouldWait;
  301.     /*
  302.      * Due to memory limitations we structure this so we malloc()
  303.      * outside the handle monitor lock.  That way we can still
  304.      * sync the disks if malloc fails.
  305.      * 1. Try a fetch.  This returns a locked handle, or NIL.
  306.      * 2. Allocate memory for the new handle.
  307.      * 3. Install the handle in the table.
  308.      * 4. If the install fails we do LRU replacment and loop to step 1.
  309.      */
  310.     if (cantBlock) { 
  311.         hdrPtr = Fsutil_HandleFetchNoWait(fileIDPtr, &wouldWait);
  312.         if ((hdrPtr == (Fs_HandleHeader *)NIL) && wouldWait) {
  313.         *hdrPtrPtr = hdrPtr;
  314.         return TRUE;
  315.         }
  316.     } else {
  317.         hdrPtr = Fsutil_HandleFetch(fileIDPtr);
  318.     }
  319.     if (hdrPtr != (Fs_HandleHeader *)NIL) {
  320.         found = TRUE;
  321.         break;
  322.     }
  323.     found = FALSE;
  324.     if (newHdrPtr == (Fs_HandleHeader *)NIL) {
  325.         newHdrPtr = (Fs_HandleHeader *)malloc(size);
  326.         if (name != (char *)NIL) {
  327.         newHdrPtr->name = (char *)malloc(strlen(name) + 1);
  328.         (void)strcpy(newHdrPtr->name, name);
  329.         } else {
  330.         newHdrPtr->name = (char *)NIL;
  331.         }
  332.     }
  333.     hdrPtr = newHdrPtr;
  334.     tableFull = HandleInstallInt(fileIDPtr, fs_Stats.handle.maxNumber,
  335.                      &hdrPtr, &found, returnLocked);
  336.     if (tableFull) {
  337.         /*
  338.          * Size limit would be exceeded.  Recycle some handles.  The
  339.          * new handle has not been installed into the hash table yet.
  340.          */
  341.         numScavenged = 0;
  342.         fs_Stats.handle.lruScans++;
  343.         for (hdrPtr = GetNextLRUHandle();
  344.          hdrPtr != (Fs_HandleHeader *)NIL;
  345.          hdrPtr = GetNextLRUHandle()) {
  346.         if ((*fsio_StreamOpTable[hdrPtr->fileID.type].scavenge)(hdrPtr)) {
  347.             numScavenged++;
  348.             fs_Stats.handle.lruHits++;
  349.             if (numScavenged >= handleScavengeThreashold) {
  350.             break;
  351.             }
  352.         } else {
  353.             fs_Stats.handle.lruChecks++;
  354.         }
  355.         }
  356.         /*
  357.          * Finish LRU, grow the table if needed, and then
  358.          * loop back and try to fetch or install the handle again.
  359.          */
  360.         DoneLRU(numScavenged);
  361.         hdrPtr = (Fs_HandleHeader *)NIL;
  362.     }
  363.     } while (hdrPtr == (Fs_HandleHeader *)NIL);
  364.  
  365.     if (found) {
  366.     /*
  367.      * Handle exists. Free up the handle we may have allocated.
  368.      * Adjust the name on the handle we found if we have a better one.
  369.      */
  370.     fs_Stats.handle.installHits++;
  371.     if (newHdrPtr != (Fs_HandleHeader *)NIL) {
  372.         if (newHdrPtr->name != (char *)NIL) {
  373.         free(newHdrPtr->name);
  374.         }
  375.         free((Address)newHdrPtr);
  376.     }
  377. #ifdef sun4c
  378.     if (name != (char *)NIL) {
  379.         if (hdrPtr->name != (char *) NIL) {
  380.         free(hdrPtr->name);
  381.         }
  382.         hdrPtr->name = (char *)malloc(strlen(name) + 1);
  383.         (void)strcpy(hdrPtr->name, name);
  384.     }
  385. #else
  386.     if ((hdrPtr->name == (char *)NIL) && (name != (char *)NIL)) {
  387.         hdrPtr->name = (char *)malloc(strlen(name) + 1);
  388.         (void)strcpy(hdrPtr->name, name);
  389.     }
  390. #endif /* sun4c */
  391.     }
  392.     *hdrPtrPtr = hdrPtr;
  393.     return(found);
  394. }
  395.  
  396. /*
  397.  *----------------------------------------------------------------------------
  398.  *
  399.  * HandleInstallInt --
  400.  *
  401.  *      Install a file handle.  This enforces a soft limit on the number
  402.  *    of handles that can exist.  Our caller has to allocate space for
  403.  *    the handle.
  404.  *
  405.  * Results:
  406.  *    TRUE is returned if the file handle table was full and our
  407.  *    caller should do LRU replacement on the table.
  408.  *    *foundPtr is set to TRUE if the handle was found.  This is possible
  409.  *    on a multiprossor even if our caller has first tried a fetch.
  410.  *
  411.  * Side effects:
  412.  *    The new handle is installed into the hash table.
  413.  *
  414.  *----------------------------------------------------------------------------
  415.  *
  416.  */
  417. ENTRY Boolean
  418. HandleInstallInt(fileIDPtr, handleLimit, hdrPtrPtr, foundPtr, returnLocked)
  419.     register Fs_FileID    *fileIDPtr;    /* Identfies handle to install. */
  420.     unsigned int    handleLimit;    /* Determines how many handles can
  421.                      * exist before we return NULL */
  422.     Fs_HandleHeader    **hdrPtrPtr;    /* In - handle to install into table
  423.                      * Out - handle found in table. */    
  424.     Boolean        *foundPtr;    /* TRUE upon return if handle found */
  425.     Boolean        returnLocked;    /* TRUE the handle is locked upon
  426.                      * return.  Otherwise it is not
  427.                      * locked, but its reference count
  428.                      * is up so it won't go away. */
  429. {
  430.     register    Hash_Entry    *hashEntryPtr;
  431.     register    Fs_HandleHeader    *hdrPtr;
  432.     Boolean            tableFull = FALSE;
  433.     Boolean            found;
  434.  
  435.     LOCK_MONITOR;
  436. again:
  437.     if (fs_Stats.handle.exists >= handleLimit) {
  438.     /*
  439.      * Creating a handle will push us past the soft limit on handles.
  440.      * We just look into the hash table, but do not create a new
  441.      * entry if the handle isn't found.
  442.      */
  443.     hashEntryPtr = Hash_LookOnly(fileHashTable, (Address) fileIDPtr);
  444.     if (hashEntryPtr == (Hash_Entry *)NIL) {
  445.         /*
  446.          * Table is full so our caller has to do LRU replacement.
  447.          * If LRU is already in progress we wait so there is only
  448.          * one process scanning the table at a time.
  449.          */
  450.         if (lruInProgress) {
  451.         do {
  452.             (void)Sync_Wait(&lruDone, FALSE);
  453.         } while (lruInProgress);
  454.         goto again;
  455.         } else {
  456.         lruInProgress = TRUE;
  457.         lruHandlesChecked = 0;
  458.         found = FALSE;
  459.         tableFull = TRUE;
  460.         goto exit;
  461.         }
  462.     }
  463.     } else {
  464.     /*
  465.      * Lookup the handle.  If a hash table entry doesn't exist
  466.      * it will be created by Hash_Find.
  467.      */
  468.     hashEntryPtr = Hash_Find(fileHashTable, (Address) fileIDPtr);
  469.     }
  470.     if (hashEntryPtr->value == (Address) NIL) {
  471.     /*
  472.      * Initialize the newly created file handle.  Our caller has
  473.      * allocated the space for the new handle.
  474.      */
  475.     hdrPtr = *hdrPtrPtr;
  476.     Hash_SetValue(hashEntryPtr, hdrPtr);
  477.     found = FALSE;
  478.     fs_Stats.handle.created++;
  479.     fs_Stats.handle.exists++;
  480.  
  481.     hdrPtr->fileID = *fileIDPtr;
  482.     hdrPtr->flags = FS_HANDLE_INSTALLED;
  483.     hdrPtr->unlocked.waiting = FALSE;
  484.     hdrPtr->refCount = 1;
  485.     /*
  486.      * Put the handle in the LRU list only if it has a scavenging
  487.      * routine defined for it.  This allows us to avoid checking
  488.      * un-reclaimable things.
  489.      */
  490.     if (fsio_StreamOpTable[fileIDPtr->type].scavenge != (Boolean (*)())NIL) {
  491.         List_InitElement(&hdrPtr->lruLinks);
  492.         List_Insert(&hdrPtr->lruLinks, LIST_ATREAR(lruList));
  493.         fs_Stats.handle.lruEntries++;
  494.     } else {
  495.         hdrPtr->lruLinks.nextPtr = (List_Links *)NIL;
  496.         hdrPtr->lruLinks.prevPtr = (List_Links *)NIL;
  497.     }
  498.     FSUTIL_TRACE_HANDLE(FSUTIL_TRACE_INSTALL_NEW, hdrPtr);
  499.     } else {
  500.     hdrPtr = (Fs_HandleHeader *) Hash_GetValue(hashEntryPtr);
  501.     if (hdrPtr->flags & FS_HANDLE_LOCKED) {
  502.         /*
  503.          * Wait for it to become unlocked.  We can't increment the
  504.          * the reference count until it is unlocked because it
  505.          * may be getting deleted.  If its locked we wait and retry.
  506.          */
  507.         (void) Sync_Wait(&hdrPtr->unlocked, FALSE);
  508.         fs_Stats.handle.lockWaits++;
  509.         goto again;
  510.     }
  511.     found = TRUE;
  512.     hdrPtr->refCount++;
  513.     MOVE_HANDLE(hdrPtr);
  514.     FSUTIL_TRACE_HANDLE(FSUTIL_TRACE_INSTALL_HIT, hdrPtr);
  515.     *hdrPtrPtr = hdrPtr;
  516.     }
  517.     if (returnLocked) {
  518.     LOCK_HANDLE(hdrPtr);
  519.     }
  520. exit:
  521.     *foundPtr = found;
  522.     UNLOCK_MONITOR;
  523.     return(tableFull);
  524. }
  525.  
  526. /*
  527.  *----------------------------------------------------------------------------
  528.  *
  529.  * Fsutil_HandleFetch --
  530.  * Fsutil_HandleFetchType --
  531.  *
  532.  *    Return a pointer to a file handle out of the file handle hash table.  
  533.  *    If no file handle is found then NIL is returned.  If one is found
  534.  *    then it is returned locked.  The reference count is increased
  535.  *    on the handle so it needs to be released with Fsutil_HandleRelease.
  536.  *    Fsutil_HandleFetchType is a macro that does type casting, see fsInt.h 
  537.  *
  538.  * Results:
  539.  *    A pointer to a file handle, NIL if none found.
  540.  *
  541.  * Side effects:
  542.  *    Locks the handle and increments its reference count.  The handle
  543.  *    is also moved to the end of the LRU list.
  544.  *
  545.  *----------------------------------------------------------------------------
  546.  *
  547.  */
  548. ENTRY Fs_HandleHeader *
  549. Fsutil_HandleFetch(fileIDPtr)
  550.     Fs_FileID     *fileIDPtr;    /* Identfies handle to fetch. */
  551. {
  552.     Hash_Entry    *hashEntryPtr;
  553.     Fs_HandleHeader    *hdrPtr;
  554.  
  555.     LOCK_MONITOR;
  556.  
  557.     fs_Stats.handle.fetchCalls++;
  558.  
  559. again:
  560.     /*
  561.      * Look in the hash table.  A bucket might have been installed by
  562.      * Fsutil_HandleInstall, but the value might be NIL because the
  563.      * handle table's size would have been exceeded by creating the handle.
  564.      */
  565.     hdrPtr = (Fs_HandleHeader *)NIL;
  566.     hashEntryPtr = Hash_LookOnly(fileHashTable, (Address) fileIDPtr);
  567.     if (hashEntryPtr != (Hash_Entry *) NIL) {
  568.     hdrPtr = (Fs_HandleHeader *) Hash_GetValue(hashEntryPtr);
  569.     if (hdrPtr != (Fs_HandleHeader *)NIL) {
  570.         fs_Stats.handle.fetchHits++;
  571.         if (hdrPtr->flags & FS_HANDLE_LOCKED) {
  572.         /*
  573.          * Wait for it to become unlocked and then rehash.
  574.          * The handle could get removed before we get a chance
  575.          * to increment the reference count on it.
  576.          */
  577.         fs_Stats.handle.lockWaits++;
  578.         (void) Sync_Wait(&hdrPtr->unlocked, FALSE);
  579.         goto again;
  580.         }
  581.         MOVE_HANDLE(hdrPtr);
  582.         LOCK_HANDLE(hdrPtr);
  583.         hdrPtr->refCount++;
  584.     }
  585.     }
  586.     UNLOCK_MONITOR;
  587.     return(hdrPtr);
  588. }
  589.  
  590. /*
  591.  *----------------------------------------------------------------------------
  592.  *
  593.  * Fsutil_HandleFetchNoWait --
  594.  *
  595.  *    This routine does the same thing as Fsutil_HandleFetch except that
  596.  *    it wouldn't wait around for a handle to because unlocked.
  597.  *
  598.  * Results:
  599.  *    A pointer to a file handle, NIL if none found or handle locked.
  600.  *
  601.  * Side effects:
  602.  *    Locks the handle and increments its reference count.  The handle
  603.  *    is also moved to the end of the LRU list.
  604.  *
  605.  *----------------------------------------------------------------------------
  606.  *
  607.  */
  608. ENTRY Fs_HandleHeader *
  609. Fsutil_HandleFetchNoWait(fileIDPtr, wouldWaitPtr)
  610.     Fs_FileID     *fileIDPtr;    /* Identfies handle to fetch. */
  611.     Boolean    *wouldWaitPtr;  /* OUT: Set to TRUE if call would of waited. */
  612. {
  613.     Hash_Entry    *hashEntryPtr;
  614.     Fs_HandleHeader    *hdrPtr;
  615.  
  616.     LOCK_MONITOR;
  617.  
  618.     fs_Stats.handle.fetchCalls++;
  619.  
  620.     /*
  621.      * Look in the hash table.  A bucket might have been installed by
  622.      * Fsutil_HandleInstall, but the value might be NIL because the
  623.      * handle table's size would have been exceeded by creating the handle.
  624.      */
  625.     *wouldWaitPtr = FALSE;
  626.     hdrPtr = (Fs_HandleHeader *)NIL;
  627.     hashEntryPtr = Hash_LookOnly(fileHashTable, (Address) fileIDPtr);
  628.     if (hashEntryPtr != (Hash_Entry *) NIL) {
  629.     hdrPtr = (Fs_HandleHeader *) Hash_GetValue(hashEntryPtr);
  630.     if (hdrPtr != (Fs_HandleHeader *)NIL) {
  631.         fs_Stats.handle.fetchHits++;
  632.         if (hdrPtr->flags & FS_HANDLE_LOCKED) {
  633.         *wouldWaitPtr = TRUE;
  634.         UNLOCK_MONITOR;
  635.         return (Fs_HandleHeader *) NIL;
  636.         }
  637.         MOVE_HANDLE(hdrPtr);
  638.         LOCK_HANDLE(hdrPtr);
  639.         hdrPtr->refCount++;
  640.     }
  641.     }
  642.     UNLOCK_MONITOR;
  643.     return(hdrPtr);
  644. }
  645.  
  646. /*
  647.  *----------------------------------------------------------------------------
  648.  *
  649.  * Fsutil_HandleLockHdr --
  650.  * Fsutil_HandleLock --
  651.  *
  652.  *    Get a lock on the handle.  Fsutil_HandleLock is a macro defined in fsInt.h
  653.  *
  654.  * Results:
  655.  *    None.
  656.  *
  657.  * Side effects:
  658.  *    The lock bit is added to the flags field for the handle.
  659.  *
  660.  *----------------------------------------------------------------------------
  661.  *
  662.  */
  663. ENTRY void
  664. Fsutil_HandleLockHdr(hdrPtr)
  665.     register    Fs_HandleHeader    *hdrPtr;
  666. {
  667.     LOCK_MONITOR;
  668.  
  669.     LOCK_HANDLE(hdrPtr);
  670.  
  671.     UNLOCK_MONITOR;
  672. }
  673.  
  674. /*
  675.  *----------------------------------------------------------------------------
  676.  *
  677.  * Fsutil_HandleIncRefCount --
  678.  *
  679.  *    Increment the reference count on the handle.  This is used by
  680.  *    the name hash table when a handle is put there.
  681.  *
  682.  * Results:
  683.  *    None.
  684.  *
  685.  * Side effects:
  686.  *    The reference count on the handle is incremented.
  687.  *
  688.  *----------------------------------------------------------------------------
  689.  *
  690.  */
  691. ENTRY void
  692. Fsutil_HandleIncRefCount(hdrPtr, amount)
  693.     register    Fs_HandleHeader    *hdrPtr;
  694.     int             amount;
  695. {
  696.     LOCK_MONITOR;
  697.  
  698.     hdrPtr->refCount += amount;
  699.  
  700.     UNLOCK_MONITOR;
  701. }
  702.  
  703. /*
  704.  *----------------------------------------------------------------------------
  705.  *
  706.  * Fsutil_HandleDecRefCount --
  707.  *
  708.  *    Decrement the reference count on the handle.
  709.  *    This is like releasing a handle but the locks on the handle
  710.  *    are not disturbed.  This is used when removing entries from
  711.  *    the name component hash table and during migration.
  712.  *
  713.  * Results:
  714.  *    None.
  715.  *
  716.  * Side effects:
  717.  *    The reference count on the handle is decremented.
  718.  *
  719.  *----------------------------------------------------------------------------
  720.  *
  721.  */
  722. ENTRY void
  723. Fsutil_HandleDecRefCount(hdrPtr)
  724.     register    Fs_HandleHeader    *hdrPtr;
  725. {
  726.     LOCK_MONITOR;
  727.  
  728.     hdrPtr->refCount--;
  729.  
  730.     UNLOCK_MONITOR;
  731. }
  732.  
  733. /*
  734.  *----------------------------------------------------------------------------
  735.  *
  736.  * Fsutil_HandleDup --
  737.  *
  738.  *    Duplicate a reference to a handle.  This locks the handle and
  739.  *    increments the refCount.  This is used by the local lookup routine
  740.  *    as it initiates its path search.
  741.  *
  742.  * Results:
  743.  *    None.
  744.  *
  745.  * Side effects:
  746.  *    The reference count on the handle is incremented and the handle is
  747.  *    locked.
  748.  *
  749.  *----------------------------------------------------------------------------
  750.  *
  751.  */
  752. ENTRY Fs_HandleHeader *
  753. Fsutil_HandleDup(hdrPtr)
  754.     register    Fs_HandleHeader    *hdrPtr;
  755. {
  756.     LOCK_MONITOR;
  757.  
  758.     LOCK_HANDLE(hdrPtr);
  759.     MOVE_HANDLE(hdrPtr);
  760.     hdrPtr->refCount++;
  761.  
  762.     UNLOCK_MONITOR;
  763.     return(hdrPtr);
  764. }
  765.  
  766. /*
  767.  *----------------------------------------------------------------------------
  768.  *
  769.  * Fsutil_HandleValid --
  770.  *
  771.  *    See if a handle have been marked invalid because of recovery.
  772.  *
  773.  * Results:
  774.  *    TRUE if the handle is still good.  FALSE if it's been marked invalid.
  775.  *
  776.  * Side effects:
  777.  *    None.
  778.  *
  779.  *----------------------------------------------------------------------------
  780.  *
  781.  */
  782.  
  783. ENTRY Boolean
  784. Fsutil_HandleValid(hdrPtr)
  785.     register Fs_HandleHeader *hdrPtr;    /* Handle to check. */
  786. {
  787.     register Boolean valid;
  788.     LOCK_MONITOR;
  789.     valid = ( (hdrPtr->flags & FS_HANDLE_INVALID) == 0 );
  790.     UNLOCK_MONITOR;
  791.     return(valid);
  792. }
  793.  
  794. /*
  795.  *----------------------------------------------------------------------------
  796.  *
  797.  * Fsutil_HandleUnlockHdr --
  798.  * Fsutil_HandleUnlock --
  799.  *
  800.  *    Release the lock on the handle. Fsutil_HandleUnlock is a macro defined
  801.  *    in fsInt.h that does type casting.
  802.  *
  803.  * Results:
  804.  *    FALSE because this is used as a scavenging no-op.
  805.  *
  806.  * Side effects:
  807.  *    The lock bit is removed from the flags filed for the handle.
  808.  *
  809.  *----------------------------------------------------------------------------
  810.  *
  811.  */
  812. ENTRY Boolean
  813. Fsutil_HandleUnlockHdr(hdrPtr)
  814.     register    Fs_HandleHeader    *hdrPtr;
  815. {
  816.     LOCK_MONITOR;
  817.  
  818.     if ((hdrPtr->flags & FS_HANDLE_LOCKED) == 0) {
  819.     UNLOCK_MONITOR;
  820.     panic( "HandleUnlock, un-locked handle\n");
  821.     return(FALSE);
  822.     }
  823.     UNLOCK_HANDLE(hdrPtr);
  824.  
  825.     UNLOCK_MONITOR;
  826.     return(FALSE);
  827. }
  828.  
  829. /*
  830.  *----------------------------------------------------------------------------
  831.  *
  832.  * Fsutil_HandleReleaseHdr --
  833.  * Fsutil_HandleRelease --
  834.  *
  835.  *    Fsutil_HandleRelease is a macro that does type casting, see fsInt.h
  836.  *    Decrement the reference count on the file handle.  The caller specifies
  837.  *    if the handle is already locked, in which case it is unlocked.
  838.  *
  839.  * Results:
  840.  *    None.
  841.  *
  842.  * Side effects:
  843.  *    The reference count is decremented.  If the reference count goes
  844.  *    to zero    and the handle has been removed then it gets nuked here.
  845.  *
  846.  *----------------------------------------------------------------------------
  847.  *
  848.  */
  849. ENTRY void
  850. Fsutil_HandleReleaseHdr(hdrPtr, locked)
  851.     register Fs_HandleHeader *hdrPtr;  /* Header of handle to release. */
  852.     Boolean          locked;       /* TRUE if the handle is already locked. */
  853. {
  854.     LOCK_MONITOR;
  855.     fs_Stats.handle.release++;
  856.  
  857.     if (locked && ((hdrPtr->flags & FS_HANDLE_LOCKED) == 0)) {
  858.     UNLOCK_MONITOR;
  859.     panic("HandleRelease, handle <%d,%d,%d,%d> \"%s\" not locked\n",
  860.         hdrPtr->fileID.type, hdrPtr->fileID.serverID,
  861.         hdrPtr->fileID.major, hdrPtr->fileID.minor, HDR_FILE_NAME(hdrPtr));
  862.     return;
  863.     }
  864.     hdrPtr->refCount--;
  865.  
  866.     if (hdrPtr->refCount < 0) {
  867.     UNLOCK_MONITOR;
  868.     panic("refCount %d on %s handle <%d,%d,%d> \"%s\"\n",
  869.         hdrPtr->refCount, Fsutil_FileTypeToString(hdrPtr->fileID.type),
  870.         hdrPtr->fileID.serverID, hdrPtr->fileID.major,
  871.         hdrPtr->fileID.minor, HDR_FILE_NAME(hdrPtr));
  872.     return;
  873.     } else if ((hdrPtr->refCount == 0) &&
  874.            (hdrPtr->flags & FS_HANDLE_REMOVED)) {
  875.     /*
  876.      * The handle has been removed, and we are the last reference.
  877.      */
  878.     fs_Stats.handle.limbo--;
  879.     FSUTIL_TRACE_HANDLE(FSUTIL_TRACE_RELEASE_FREE, hdrPtr);
  880.         REMOVE_HANDLE(hdrPtr);
  881.      } else {
  882.     FSUTIL_TRACE_HANDLE(FSUTIL_TRACE_RELEASE_LEAVE, hdrPtr);
  883.     if (locked) {
  884.         UNLOCK_HANDLE(hdrPtr);
  885.     }
  886.     }
  887.     UNLOCK_MONITOR;
  888. }
  889.  
  890. /*
  891.  *----------------------------------------------------------------------------
  892.  *
  893.  * Fsutil_HandleRemoveInt --
  894.  *
  895.  *    Delete the handle from hash table.  The internal version that
  896.  *    knows it's under the monitor lock.  This can be called while
  897.  *    the handle still has references.  It unlocks the handle
  898.  *    and frees it if there are not references
  899.  *
  900.  * Results:
  901.  *    None.
  902.  *
  903.  * Side effects:
  904.  *    The file handle is deleted out of the hash table, and memory is freed
  905.  *    if there are no references to the handle.
  906.  *
  907.  *----------------------------------------------------------------------------
  908.  *
  909.  */
  910. INTERNAL void
  911. Fsutil_HandleRemoveInt(hdrPtr)
  912.     register Fs_HandleHeader *hdrPtr;  /* Header of handle to remove. */
  913. {
  914.     register    Hash_Entry    *hashEntryPtr;
  915.  
  916.     if (!(hdrPtr->flags & FS_HANDLE_INVALID)) {
  917.     hashEntryPtr = Hash_LookOnly(fileHashTable, (Address) &hdrPtr->fileID);
  918.     if (hashEntryPtr == (Hash_Entry *) NIL) {
  919.         UNLOCK_MONITOR;
  920.         panic("Fsutil_HandleRemoveInt: Couldn't find handle in hash table.\n");
  921.         LOCK_MONITOR;
  922.         return;
  923.     }
  924.     Hash_SetValue(hashEntryPtr, NIL);
  925.     Hash_Delete(fileHashTable, hashEntryPtr);
  926.     }
  927.     fs_Stats.handle.exists--;
  928.  
  929.     /*
  930.      * Wakeup anyone waiting for this handle to become unlocked.
  931.      */
  932.     UNLOCK_HANDLE(hdrPtr);
  933.  
  934.     if (hdrPtr->refCount > 0) {
  935.     /*
  936.      * We've removed the handle from the hash table so it won't
  937.      * be found, but someone has a reference to it.  HandleRelease
  938.      * will free the handle for us later.
  939.      */
  940.     fs_Stats.handle.limbo++;
  941.     FSUTIL_TRACE_HANDLE(FSUTIL_TRACE_REMOVE_LEAVE, hdrPtr);
  942.     hdrPtr->flags |= FS_HANDLE_REMOVED;
  943.     } else {
  944.     FSUTIL_TRACE_HANDLE(FSUTIL_TRACE_REMOVE_FREE, hdrPtr);
  945.     REMOVE_HANDLE(hdrPtr);
  946.     }
  947. }
  948.  
  949. /*
  950.  *----------------------------------------------------------------------------
  951.  *
  952.  * Fsutil_HandleRemove --
  953.  * Fsutil_HandleRemoveHdr --
  954.  *
  955.  *    Delete the handle from hash table by calling the internal routine.
  956.  *    Fsutil_HandleRemove is a macro defined in fsInt.h that does type casting.
  957.  *    Removing a handle deletes it from the hash table and unlocks it.
  958.  *    Then, if there are no references to the handle it is freed.  Otherwise
  959.  *    it is marked as deleted and Fsutil_HandleRelease cleans it up.
  960.  *
  961.  * Results:
  962.  *    None.
  963.  *
  964.  * Side effects:
  965.  *    None (see Fsutil_HandleRemoveInt).
  966.  *
  967.  *----------------------------------------------------------------------------
  968.  *
  969.  */
  970.  
  971. ENTRY void
  972. Fsutil_HandleRemoveHdr(hdrPtr)
  973.     register Fs_HandleHeader *hdrPtr;    /* Handle to remove. */
  974. {
  975.     LOCK_MONITOR;
  976.     Fsutil_HandleRemoveInt(hdrPtr);
  977.     UNLOCK_MONITOR;
  978. }
  979.  
  980. /*
  981.  *----------------------------------------------------------------------------
  982.  *
  983.  * Fsutil_HandleAttemptRemove --
  984.  *
  985.  *    Like Fsutil_HandleRemove, but specific to local file handles because
  986.  *    they might have extra references from the name component cache.
  987.  *    This will not remove the handle if it is still referenced from
  988.  *    that cache.  The reference count has to be checked inside the
  989.  *    monitor to avoid multi-processor races.    This routine is called by the
  990.  *    scavenging routines if they think it's probably ok to remove the handle.
  991.  *
  992.  * Results:
  993.  *    TRUE if it actually removed the handle.
  994.  *
  995.  * Side effects:
  996.  *    Frees the memory for the handles file descriptor.
  997.  *
  998.  *----------------------------------------------------------------------------
  999.  *
  1000.  */
  1001.  
  1002. ENTRY Boolean
  1003. Fsutil_HandleAttemptRemove(hdrPtr)
  1004.     Fs_HandleHeader *hdrPtr; /* Handle to try and remove. */
  1005. {
  1006.     register Fsio_FileIOHandle *handlePtr;    
  1007.     register Boolean removed;
  1008.  
  1009.     handlePtr = (Fsio_FileIOHandle *) hdrPtr;
  1010.     LOCK_MONITOR;
  1011.     if (handlePtr->hdr.refCount == 0) {
  1012.     free((Address)handlePtr->descPtr);
  1013.     handlePtr->descPtr = (Fsdm_FileDescriptor *)NIL;
  1014.     Fsio_FileSyncLockCleanup(handlePtr);
  1015.     Fsutil_HandleRemoveInt((Fs_HandleHeader *)handlePtr);
  1016.     removed = TRUE;
  1017.     } else {
  1018.     removed = FALSE;
  1019.     UNLOCK_HANDLE((Fs_HandleHeader *)handlePtr);
  1020.     }
  1021.     UNLOCK_MONITOR;
  1022.     return(removed);
  1023. }
  1024.  
  1025. /*
  1026.  *----------------------------------------------------------------------------
  1027.  *
  1028.  * Fsutil_GetNextHandle --
  1029.  *
  1030.  *    Get the next handle in the hash table.  Return the handle locked.
  1031.  *    The hashSearchPtr is initialized with Hash_StartSearch.  This
  1032.  *    always skips locked handles.  The users of this routine are:
  1033.  *    recovery stuff:  it is important not to block recovery as
  1034.  *        that ends up hanging the whole machine.
  1035.  *    unmounting a disk: this is a rare operation, but it should not
  1036.  *        be hung-up by a wedged handle.
  1037.  *    scavenging:  if a handle is locked, then it should not
  1038.  *        be scavenged anyway.
  1039.  *
  1040.  * Results:
  1041.  *    The next handle in the hash table.
  1042.  *
  1043.  * Side effects:
  1044.  *    Locks the handle (but does not increment its reference count).
  1045.  *    This prints a warning if a handle is skipped when locked.
  1046.  *
  1047.  *----------------------------------------------------------------------------
  1048.  *
  1049.  */
  1050.  
  1051. ENTRY Fs_HandleHeader *
  1052. Fsutil_GetNextHandle(hashSearchPtr)
  1053.     Hash_Search    *hashSearchPtr;    /* Iterator for going through the hash table. */
  1054. {
  1055.     register     Fs_HandleHeader    *hdrPtr;
  1056.     register    Hash_Entry    *hashEntryPtr;
  1057.  
  1058.     LOCK_MONITOR;
  1059.  
  1060.     for (hashEntryPtr = Hash_Next(fileHashTable, hashSearchPtr);
  1061.          hashEntryPtr != (Hash_Entry *) NIL;  
  1062.      hashEntryPtr = Hash_Next(fileHashTable, hashSearchPtr)) {
  1063.     hdrPtr = (Fs_HandleHeader *) Hash_GetValue(hashEntryPtr);
  1064.     if (hdrPtr == (Fs_HandleHeader *)NIL) {
  1065.         /*
  1066.          * Caught handle in the process of being installed.
  1067.          */
  1068.         continue;
  1069.     }
  1070.     /*
  1071.      * Skip locked handles to avoid hanging the system on locked handle. 
  1072.      */
  1073.     if (hdrPtr->flags & FS_HANDLE_LOCKED) {
  1074.         continue;
  1075.     }
  1076.     if (hdrPtr->flags & (FS_HANDLE_INVALID|FS_HANDLE_REMOVED)) {
  1077.         continue;
  1078.     }
  1079.     LOCK_HANDLE(hdrPtr);
  1080.     UNLOCK_MONITOR;
  1081.     return(hdrPtr);
  1082.     }
  1083.  
  1084.     UNLOCK_MONITOR;
  1085.     return((Fs_HandleHeader *) NIL);
  1086. }
  1087.  
  1088. /*
  1089.  *----------------------------------------------------------------------------
  1090.  *
  1091.  * GetNextLRUHandle --
  1092.  *
  1093.  *    Get the next handle in the LRU list.  Return the handle locked.
  1094.  *    This skips locked handles because they are obviously in use and not good
  1095.  *    candidates for removal.  This also prevents a single locked handle
  1096.  *    from clogging up the system.
  1097.  *
  1098.  * Results:
  1099.  *    The next handle in the LRU list.
  1100.  *
  1101.  * Side effects:
  1102.  *    Increments the number of handles checked in this LRU scan so
  1103.  *    we know when to terminate.
  1104.  *
  1105.  *----------------------------------------------------------------------------
  1106.  *
  1107.  */
  1108. ENTRY Fs_HandleHeader *
  1109. GetNextLRUHandle()
  1110. {
  1111.     register     Fs_HandleHeader    *hdrPtr;
  1112.     register    List_Links    *listPtr;
  1113.  
  1114.     LOCK_MONITOR;
  1115.     if (lruHandlesChecked >= fs_Stats.handle.maxNumber) {
  1116.     hdrPtr = (Fs_HandleHeader *)NIL;
  1117.     goto exit;
  1118.     }
  1119.     /*
  1120.      * Get the candidate handle and move it to the young end of
  1121.      * the list in case it is not replaced.
  1122.      */
  1123.     listPtr = List_First(lruList);
  1124.     hdrPtr = LRU_LINKS_TO_HANDLE(listPtr);
  1125.     MOVE_HANDLE(hdrPtr);
  1126.     lruHandlesChecked++;
  1127.     /*
  1128.      * Now skip over locked and removed handles, moving them to the "young" end.
  1129.      */
  1130.     while (hdrPtr->flags & (FS_HANDLE_REMOVED|FS_HANDLE_LOCKED)) {
  1131.     if (lruHandlesChecked >= fs_Stats.handle.maxNumber) {
  1132.         hdrPtr = (Fs_HandleHeader *)NIL;
  1133.         goto exit;
  1134.     } else {
  1135.         listPtr = List_First(lruList);
  1136.         hdrPtr = LRU_LINKS_TO_HANDLE(listPtr);
  1137.         MOVE_HANDLE(hdrPtr);
  1138.     }
  1139.     lruHandlesChecked++;
  1140.     }
  1141.     LOCK_HANDLE(hdrPtr);
  1142. exit:
  1143.     UNLOCK_MONITOR;
  1144.     return(hdrPtr);
  1145. }
  1146.  
  1147. /*
  1148.  *----------------------------------------------------------------------------
  1149.  *
  1150.  * DoneLRU --
  1151.  *
  1152.  *    Terminate LRU iteration.  This grows the table if needed and
  1153.  *    then notifies anyone waiting for LRU replacement to finish.
  1154.  *
  1155.  * Results:
  1156.  *    None.
  1157.  *
  1158.  * Side effects:
  1159.  *    Grows the table if it needs to be grown.
  1160.  *
  1161.  *----------------------------------------------------------------------------
  1162.  *
  1163.  */
  1164. ENTRY void
  1165. DoneLRU(numScavenged)
  1166.     int numScavenged;        /* Number of handles replaced */
  1167. {
  1168.     LOCK_MONITOR;
  1169.     if (numScavenged == 0) {
  1170.     /*
  1171.      * Grow the table a bit because no handles could be reclaimed.
  1172.      */
  1173.     fs_Stats.handle.maxNumber += handleLimitInc;
  1174.     handleLimitInc = LIMIT_INC(fs_Stats.handle.maxNumber);
  1175.     handleScavengeThreashold = THREASHOLD(fs_Stats.handle.maxNumber);
  1176.     }
  1177.     lruInProgress = FALSE;
  1178.     Sync_Broadcast(&lruDone);
  1179.     UNLOCK_MONITOR;
  1180. }
  1181.  
  1182. /*
  1183.  *----------------------------------------------------------------------------
  1184.  *
  1185.  * Fsutil_HandleInvalidate --
  1186.  *
  1187.  *    Mark a handle as bogus because of a failed recovery attempt.
  1188.  *
  1189.  * Results:
  1190.  *    None.
  1191.  *
  1192.  * Side effects:
  1193.  *    Sets the INVALID flag in the handle, negates the minor
  1194.  *    field of the fileID so that the handle won't get found,
  1195.  *    removes the handle from the hash table.
  1196.  *
  1197.  *----------------------------------------------------------------------------
  1198.  *
  1199.  */
  1200. ENTRY void
  1201. Fsutil_HandleInvalidate(hdrPtr)
  1202.     Fs_HandleHeader *hdrPtr;
  1203. {
  1204.     Hash_Entry    *hashEntryPtr;
  1205.  
  1206.     LOCK_MONITOR;
  1207.  
  1208.     if ((hdrPtr->flags & FS_HANDLE_INVALID) == 0) {
  1209.     hdrPtr->flags |= FS_HANDLE_INVALID;
  1210.     /*
  1211.      * Invalid handles are deleted from the hash table and the fileID is
  1212.      * smashed so that all subsequent operations using this handle that
  1213.      * go to the server will fail with a stale handle return code.
  1214.      */
  1215.     hashEntryPtr = Hash_LookOnly(fileHashTable, (Address) &hdrPtr->fileID);
  1216.     if (hashEntryPtr == (Hash_Entry *) NIL) {
  1217.         UNLOCK_MONITOR;
  1218.         panic("Fsutil_HandleInvalidate: Can't find %s handle <%d,%d,%d>\n",
  1219.             Fsutil_FileTypeToString(hdrPtr->fileID.type),
  1220.             hdrPtr->fileID.serverID,
  1221.             hdrPtr->fileID.major, hdrPtr->fileID.minor);
  1222.         return;
  1223.     }
  1224.     Hash_SetValue(hashEntryPtr, NIL);
  1225.     Hash_Delete(fileHashTable, hashEntryPtr);
  1226.     hdrPtr->fileID.minor = -hdrPtr->fileID.minor;
  1227.     }
  1228.  
  1229.     UNLOCK_MONITOR;
  1230. }
  1231.  
  1232.  
  1233. /*
  1234.  *----------------------------------------------------------------------------
  1235.  *
  1236.  * Fsutil_HandleDescWriteBack --
  1237.  *
  1238.  *    Go through all of the handles and write back all descriptors that
  1239.  *    are dirty and have a modify date before the given time.
  1240.  *
  1241.  * Results:
  1242.  *    The number of locked file handles.
  1243.  *
  1244.  * Side effects:
  1245.  *    The write backs.  Propogates modify times from handle to desciptor.
  1246.  *
  1247.  *----------------------------------------------------------------------------
  1248.  *
  1249.  */
  1250.  
  1251. ENTRY int
  1252. Fsutil_HandleDescWriteBack(shutdown, domain)
  1253.     Boolean    shutdown;    /* TRUE if the kernel is being shutdowned. */
  1254.     int        domain;        /* Domain number, -1 means all local domains */
  1255. {
  1256.     Hash_Search            hashSearch;
  1257.     register Fsio_FileIOHandle *handlePtr;
  1258.     register Fs_HandleHeader    *hdrPtr;
  1259.     register Hash_Entry        *hashEntryPtr;
  1260.     int                lockedDesc = 0;
  1261.  
  1262.     LOCK_MONITOR;
  1263.  
  1264.     Hash_StartSearch(&hashSearch);
  1265.  
  1266.     for (hashEntryPtr = Hash_Next(fileHashTable, &hashSearch);
  1267.          hashEntryPtr != (Hash_Entry *) NIL;  
  1268.      hashEntryPtr = Hash_Next(fileHashTable, &hashSearch)) {
  1269.     hdrPtr = (Fs_HandleHeader *) Hash_GetValue(hashEntryPtr);
  1270.     if (hdrPtr == (Fs_HandleHeader *)NIL) {
  1271.         /*
  1272.          * Handle has been removed.
  1273.          */
  1274.         continue;
  1275.     }
  1276.     if (hdrPtr->fileID.type != FSIO_LCL_FILE_STREAM) {
  1277.         continue;
  1278.     }
  1279.     if (domain >= 0 && hdrPtr->fileID.major != domain) {
  1280.         continue;
  1281.     }
  1282.     if (hdrPtr->flags & FS_HANDLE_LOCKED) {
  1283.         lockedDesc++;
  1284.         continue;
  1285.     }
  1286.     handlePtr = (Fsio_FileIOHandle *)hdrPtr;
  1287.     if (handlePtr->descPtr == (Fsdm_FileDescriptor *)NIL) {
  1288.         printf("Fsutil_HandleDescWriteBack, no descPtr for <%d,%d> \"%s\"\n",
  1289.         hdrPtr->fileID.major, hdrPtr->fileID.minor,
  1290.         Fsutil_HandleName(hdrPtr));
  1291.         continue;
  1292.     }
  1293.     (void)Fsdm_FileDescWriteBack(handlePtr, FALSE);
  1294.     }
  1295.  
  1296.     if (shutdown & lockedDesc) {
  1297.     printf("Fsutil_HandleDescWriteBack: %d descriptors still locked\n",
  1298.             lockedDesc);
  1299.     }
  1300.  
  1301.     UNLOCK_MONITOR;
  1302.  
  1303.     return(lockedDesc);
  1304. }
  1305.  
  1306.